import { lineString, length, polygon, centroid, area } from "@turf/turf";
import { Billboard, Label, CallbackProperty, Cartesian2, Cartesian3, Cartographic, Color, Entity, HorizontalOrigin, PolygonHierarchy, ScreenSpaceEventType, VerticalOrigin, Viewer } from "cesium";
import { ControlUtils } from "./controlUtils";
import { CoordUtils } from "./coordUtils";
import { ModelUtils } from "./modelUtils";


export class MeasureUtils {
    /* 测量点相关属性 */
    private __removePointMeasureResult: (() => void) | undefined

    /* 线段距离测量相关属性 */
    private __polylineCoords: Cartesian3[] = [] // polyline点列表
    private __dynamicPolyline: Entity | null = null // 动态绘制的polyline
    private __polylineBillboards: Billboard[] = []  // polyline的点的广告牌
    private __polylineLabels: Label[] = [] // polyline的点的label
    private __polyline: Entity | null = null
    private __polylineLeftClick: (() => void) | undefined
    private __polylineMouseMove: (() => void) | undefined
    private __polylineRightClick: (() => void) | undefined

    /* polygon面积测量相关属性 */
    private __polygonCoords: Cartesian3[] = []
    private __dynamicPolygon: Entity | null = null
    private __polygonBillboards: Billboard[] = []
    private __polygon: Entity | null = null
    private __polygonLabel: Label | null = null
    private __polygonLeftClick: (() => void) | undefined
    private __polygonMouseMove: (() => void) | undefined
    private __polygonRightClick: (() => void) | undefined

    constructor(private viewer: Viewer, private controlUtils: ControlUtils, private modelUtils: ModelUtils, private coordUtils: CoordUtils) {

    }
    /**
     * 启用点测量
     * @param measuredCallback 测量完成回调函数(因为这里返回了billboard和label，可以通过更改属性自定义样式)
     * @returns 清除并禁用点测量
     */
    enableMeasurePoint(measuredCallback: ((poi: {
        billboard: Billboard,
        label: Label
    }) => void) = () => {}) {
        let billboard: Billboard;
        let label: Label
        const removeClickGetCoord = this.controlUtils.addMouseEventWatch((event: any) => {

            /* 判断之前是否有测量结果，有的话就把之前的测量结果删掉 */
            if (this.__removePointMeasureResult) this.__removePointMeasureResult();

            /* 获取点击的坐标 */
            const pick = this.viewer.scene.pickPosition(event.position);
            const degrees = this.coordUtils.cato2Lat(Cartographic.fromCartesian(pick));
            degrees.height += 1;

            /* 根据点击的坐标获取 */
            billboard = this.modelUtils.addBillboard({
                image: ``,
                position: Cartesian3.fromDegrees(degrees.longitude, degrees.latitude, degrees.height),
                scale: 0.4,
                eyeOffset: new Cartesian3(0, 0, -14)
            })
            label = this.modelUtils.addLabel({
                text: `经度:${degrees.longitude} 维度:${degrees.latitude} 高度:${degrees.height}`,
                position: Cartesian3.fromDegrees(degrees.longitude, degrees.latitude, degrees.height),
                font: "16px 雅黑",
                horizontalOrigin: HorizontalOrigin.CENTER,
                verticalOrigin: VerticalOrigin.BOTTOM,
                pixelOffset: new Cartesian2(0, -18),
                backgroundColor: Color.BLACK.withAlpha(0.51),
                showBackground: true,
                backgroundPadding: new Cartesian2(19, 5),
                eyeOffset: new Cartesian3(0, 0, -14)
            })

            /* 测量完成的回调，返回添加到场景的内容 */
            measuredCallback({
                billboard,
                label
            });

            /* 给类中移除点测量结果的函数赋值 */
            this.__removePointMeasureResult = () => {
                this.modelUtils.removeBillboard(billboard);
                this.modelUtils.removeLabel(label);
                this.__removePointMeasureResult = undefined;
            }
        }, ScreenSpaceEventType.LEFT_CLICK)
        return () => {
            removeClickGetCoord(); // 移除点击事件
            if (this.__removePointMeasureResult) this.__removePointMeasureResult(); // 移除测量结果
        }
    }
    /**
     * 启用线段距离测量
     * @returns 
     */
    enableMeasurePolylineDistance() {
        this.__polylineLeftClick = this.measurePolylineDistanceLeftClick();
        this.__polylineMouseMove = this.measurePolylineDistanceMouseMove();
        this.__polylineRightClick = this.measurePolylineDistanceRightClick();
        return () => {
            // 移除正在绘制多的polyline
            if (this.__dynamicPolyline) {
                this.viewer.entities.remove(this.__dynamicPolyline)
                this.__dynamicPolyline = null;
            }

            // 移除所有billboard
            if (this.__polylineBillboards.length > 0) {
                this.__polylineBillboards.forEach(billboard => {
                    this.modelUtils.removeBillboard(billboard);
                })
                this.__polylineBillboards = [];
            }
            // 移除所有label
            if (this.__polylineLabels.length > 0) {
                this.__polylineLabels.forEach(label => {
                    this.modelUtils.removeLabel(label)
                })
                this.__polylineLabels = [];
            }
            if (this.__polyline) {
                this.viewer.entities.remove(this.__polyline)
                this.__polyline = null;
            }
            // 清空坐标点
            this.__polylineCoords = []
            // 移除所有鼠标事件
            if(this.__polylineLeftClick) {
                this.__polylineLeftClick();
                this.__polylineLeftClick = undefined;
            }
            if(this.__polylineRightClick) {
                this.__polylineRightClick();
                this.__polylineRightClick = undefined;
            }
            if(this.__polylineMouseMove) {
                this.__polylineMouseMove();
                this.__polylineMouseMove = undefined
            }
        }
    }
    /**
     * 线段测量的left click事件处理
     * @returns 
     */
    private measurePolylineDistanceLeftClick() {
        return this.controlUtils.addMouseEventWatch((event: any) => {
            const position = this.viewer.camera.pickEllipsoid(event.position, this.viewer.scene.globe.ellipsoid);
            if (position) {
                this.__polylineCoords.push(position);
                /* 1. 判断是否有正在动态绘制的polyline
                        没有： 创建一个
                        有： 不用创建了，MOUSE_MOVE会用到
                */
                if (this.__dynamicPolyline === null) {
                    this.__dynamicPolyline = this.viewer.entities.add({
                        polyline: {
                            positions: new CallbackProperty(() => {
                                return [...this.__polylineCoords]
                            }, false),
                            clampToGround: true,
                            width: 4,
                            material: new Color(79 / 255, 232 / 255, 175 / 255)
                        },
                    })
                }

                /* 
                    2. 添加点的icon
                */
                this.__polylineBillboards.push(this.modelUtils.addBillboard({
                    image: ``,
                    position: position,
                    scale: 0.6,
                    eyeOffset: new Cartesian3(0, 0, -14)
                }))

                /* 
                    3. 添加点的label
                */
                if (this.__polylineCoords.length === 1) { // 第一个点
                    // 起点
                    this.__polylineLabels.push(this.modelUtils.addLabel({
                        text: "起点",
                        position: position,
                        font: "16px 雅黑",
                        showBackground: true,
                        backgroundColor: Color.BLACK.withAlpha(0.51),
                        horizontalOrigin: HorizontalOrigin.CENTER,
                        verticalOrigin: VerticalOrigin.BOTTOM,
                        pixelOffset: new Cartesian2(0, -20),
                        eyeOffset: new Cartesian3(0, 0, -14)
                    }))
                } else {
                    const lineCoordArr: [number, number][] = [];
                    this.__polylineCoords.forEach((coord, length) => {
                        /* 因为最后一个鼠标移动动态绘制的所以要去掉 */
                        if (length === this.__polylineCoords.length - 1) return;
                        /* 处理角度经纬度传入数组 */
                        const degrees = this.coordUtils.cato2Lat(Cartographic.fromCartesian(coord))
                        lineCoordArr.push([degrees.longitude, degrees.latitude]);
                    })
                    const turfLine = lineString(lineCoordArr);
                    const turfLength = length(turfLine, {
                        units: "meters"
                    })
                    this.__polylineLabels.push(this.modelUtils.addLabel({
                        text: `${turfLength}米`,
                        position: position,
                        font: "16px 雅黑",
                        showBackground: true,
                        backgroundColor: Color.BLACK.withAlpha(0.51),
                        horizontalOrigin: HorizontalOrigin.CENTER,
                        verticalOrigin: VerticalOrigin.BOTTOM,
                        pixelOffset: new Cartesian2(0, -20),
                        eyeOffset: new Cartesian3(0, 0, -14)
                    }))
                }
            }
        }, ScreenSpaceEventType.LEFT_CLICK);
    }
    /**
     * 线段距离测量mouse move事件处理
     * @returns 
     */
    private measurePolylineDistanceMouseMove() {
        return this.controlUtils.addMouseEventWatch((event: any) => {
            const position = this.viewer.camera.pickEllipsoid(event.endPosition, this.viewer.scene.globe.ellipsoid);
            if (position) {
                /* 1. 有动态绘制的entity才需要跟随鼠标移动 */
                if (this.__dynamicPolyline) {
                    // 不止一个点才开始动态添加最后一个点
                    if (this.__polylineCoords.length > 1) {
                        // 删掉最后一个点
                        this.__polylineCoords.pop();
                    }
                    // 当前鼠标移动的位置才是最后一个点
                    this.__polylineCoords.push(position);
                }
            }
        }, ScreenSpaceEventType.MOUSE_MOVE);
    }
    /**
     * 线段距离测量right click事件处理
     * @returns 
     */
    private measurePolylineDistanceRightClick() {
        return this.controlUtils.addMouseEventWatch((event: any) => {
            if (!(this.__polylineCoords.length - 1 >= 2)) return;
            if(this.__polylineMouseMove) {
                this.__polylineMouseMove();
                this.__polylineMouseMove = undefined
            }
            if (this.__dynamicPolyline)
                this.viewer.entities.remove(this.__dynamicPolyline);
            this.__dynamicPolyline = null;
            this.__polylineCoords.pop();
            this.__polyline = this.viewer.entities.add({
                polyline: {
                    positions: [...this.__polylineCoords],
                    clampToGround: true,
                    width: 4,
                    material: new Color(79 / 255, 232 / 255, 175 / 255)
                },
            })
            this.__polylineCoords = [];
            if(this.__polylineLeftClick) {
                this.__polylineLeftClick();
                this.__polylineLeftClick = undefined;
            }
            if(this.__polylineRightClick) {
                this.__polylineRightClick();
                this.__polylineRightClick = undefined;
            }
        }, ScreenSpaceEventType.RIGHT_CLICK);
    }
    enableMeasurePolygonArea() {
        this.__polygonLeftClick = this.measurePolygonAreaLeftClick();
        this.__polygonMouseMove = this.measurePolygonAreaMouseMove();
        this.__polygonRightClick = this.measurePolygonAreaRightClick();
        return () => {
            // 移除正在绘制多的polygon
            if (this.__dynamicPolygon) {
                this.viewer.entities.remove(this.__dynamicPolygon)
                this.__dynamicPolygon = null
            }

            // 移除所有billboard
            if (this.__polygonBillboards.length > 0) {
                this.__polygonBillboards.forEach(billboard => {
                    this.modelUtils.removeBillboard(billboard);
                })
                this.__polygonBillboards = []
            }
            // 移除绘制好的polygon
            if (this.__polygon) {
                this.viewer.entities.remove(this.__polygon)
                this.__polygon = null;
            }
            // 移除面积label
            if (this.__polygonLabel) {
                this.modelUtils.removeLabel(this.__polygonLabel);
                this.__polygonLabel = null;
            }
            // 清空坐标点
            this.__polygonCoords = []
            // 移除所有鼠标事件
            if(this.__polygonLeftClick) {
                this.__polygonLeftClick();
                this.__polygonLeftClick = undefined
            }
            if(this.__polygonRightClick) {
                this.__polygonRightClick();
                this.__polygonRightClick = undefined
            }
            if(this.__polygonMouseMove) {
                this.__polygonMouseMove();
                this.__polygonMouseMove = undefined
            }
        }
    }
    private measurePolygonAreaLeftClick() {
        return this.controlUtils.addMouseEventWatch((event: any) => {
            const position = this.viewer.camera.pickEllipsoid(event.position, this.viewer.scene.globe.ellipsoid);
            if (position) {
                this.__polygonCoords.push(position);
                /* 1. 判断是否有正在动态绘制的polyline
                        没有： 创建一个
                        有： 不用创建了，MOUSE_MOVE会用到
                */
                if (this.__dynamicPolygon === null) {
                    this.__dynamicPolygon = this.viewer.entities.add({
                        polygon: {
                            // 这个方法上面有重点说明
                            hierarchy: new CallbackProperty(() => {
                                // PolygonHierarchy 定义多边形及其孔的线性环的层次结构（空间坐标数组）
                                return new PolygonHierarchy(this.__polygonCoords);
                            }, false),
                            material: new Color(79 / 255, 232 / 255, 175 / 255, 0.5),
                        },
                        polyline: {
                            positions: new CallbackProperty(() => {
                                return [...this.__polygonCoords, this.__polygonCoords[0]]
                            }, false),
                            clampToGround: true,
                            width: 4,
                            material: new Color(79 / 255, 232 / 255, 175 / 255)
                        },
                    })
                }

                /* 
                    2. 添加点的icon
                */
                this.__polygonBillboards.push(this.modelUtils.addBillboard({
                    image: ``,
                    position: position,
                    scale: 0.6,
                    eyeOffset: new Cartesian3(0, 0, -14)
                }))
            }
        }, ScreenSpaceEventType.LEFT_CLICK);
    }
    private measurePolygonAreaMouseMove() {
        return this.controlUtils.addMouseEventWatch((event: any) => {
            const position = this.viewer.camera.pickEllipsoid(event.endPosition, this.viewer.scene.globe.ellipsoid);
            if (position) {
                /* 1. 有动态绘制的entity才需要跟随鼠标移动 */
                if (this.__dynamicPolygon) {
                    // 不止一个点才开始动态添加最后一个点
                    if (this.__polygonCoords.length > 1) {
                        // 删掉最后一个点
                        this.__polygonCoords.pop();
                    }
                    // 当前鼠标移动的位置才是最后一个点
                    this.__polygonCoords.push(position);
                }
            }
        }, ScreenSpaceEventType.MOUSE_MOVE);
    }
    private measurePolygonAreaRightClick() {
        return this.controlUtils.addMouseEventWatch((event: any) => {
            if (!(this.__polygonCoords.length - 1 >= 2)) return;
            if(this.__polygonMouseMove) {
                this.__polygonMouseMove();
                this.__polygonMouseMove = undefined
            }
            if (this.__dynamicPolygon)
                this.viewer.entities.remove(this.__dynamicPolygon);
            this.__dynamicPolygon = null;
            this.__polygonCoords.pop();
            this.__polygon = this.viewer.entities.add({
                polygon: {
                    hierarchy: new PolygonHierarchy(this.__polygonCoords),
                    material: new Color(79 / 255, 232 / 255, 175 / 255, 0.5),
                },
                polyline: {
                    positions: [...this.__polygonCoords, this.__polygonCoords[0]],
                    clampToGround: true,
                    width: 4,
                    material: new Color(79 / 255, 232 / 255, 175 / 255)
                },
            })
            /* 计算多边形中心点 */
            const degreesCoords: [number, number][] = [];
            this.__polygonCoords.forEach((coord) => {
                const degrees = this.coordUtils.cato2Lat(Cartographic.fromCartesian(coord));
                degreesCoords.push([degrees.longitude, degrees.latitude]);
            })
            // 让多边形闭合
            degreesCoords.push([degreesCoords[0][0], degreesCoords[0][1]]);
            const turfPolygon = polygon([degreesCoords]);
            // 多边形中心点
            const turfCenter = centroid(turfPolygon);
            const polygonCenter = Cartesian3.fromDegrees(turfCenter.geometry.coordinates[0], turfCenter.geometry.coordinates[1])

            /* 计算多边形面积 */
            // 面积
            const measureOfArea = area(turfPolygon);
            this.__polygonLabel = this.modelUtils.addLabel({
                text: `${measureOfArea}m²`,
                position: polygonCenter,
                font: "16px 雅黑",
                showBackground: true,
                backgroundColor: Color.BLACK.withAlpha(0.51),
                horizontalOrigin: HorizontalOrigin.CENTER,
                verticalOrigin: VerticalOrigin.BOTTOM,
                pixelOffset: new Cartesian2(0, -20),
                eyeOffset: new Cartesian3(0, 0, -14)
            })
            this.__polygonCoords = [];
            if(this.__polygonLeftClick) {
                this.__polygonLeftClick();
                this.__polygonLeftClick = undefined
            }
            if(this.__polygonRightClick) {
                this.__polygonRightClick();
                this.__polygonRightClick = undefined
            }
        }, ScreenSpaceEventType.RIGHT_CLICK);
    }
}